/*
 * protocol.h - 协议头文件
 *
 * Author: xiaobo@YGL (xiaobocwb@gmail.com)
 * Version: 1.0.0
 * Date: 2024-01
 */

#ifndef __PROTOCOL_H__
#define __PROTOCOL_H__

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

// 回调函数类型
typedef void (*msg_callback_t)(uint8_t msgid, uint8_t *payload, size_t len);

// 硬件抽象层
typedef struct {
    void* dev;
    int (*send)(void* dev, uint8_t *data, uint16_t len);

    void* (*sem_new)(void);
    void (*sem_del)(void* sem);
    bool (*sem_wait)(void* sem, uint32_t wait_tick);
    void (*sem_post)(void* sem);

    void* (*mutex_new)(void);
    void (*mutex_del)(void* mutex);
    void (*mutex_lock)(void* mutex);
    void (*mutex_unlock)(void* mutex);
} protocol_hal_t;

// 协议句柄(不透明指针)
struct protocol_ctx;
typedef struct protocol_ctx* protocol_t;

// API函数声明

/**
 * 创建协议实例
 * 
 * @param hal 硬件抽象层
 * @return 协议实例
 */
protocol_t protocol_create(const protocol_hal_t *hal);

/**
 * 销毁协议实例
 * 
 * @param proto 协议实例
 */
void protocol_destroy(protocol_t proto);


/**
 * 获取设备句柄
 * 
 * @param proto 协议实例
 * @return 设备句柄
 */
void *protocol_get_dev(protocol_t proto);

/**
 * 订阅消息
 * 
 * @param proto 协议实例
 * @param msgid 消息ID(0-255)
 * @param callback 消息回调函数
 * @return true 成功
 *         false 失败
 */
bool protocol_subscribe(protocol_t proto, uint8_t msgid, msg_callback_t callback);

/**
 * 取消订阅消息
 * 
 * @param proto 协议实例
 * @param msgid 消息ID(0-255)
 * @return true 成功
 *         false 失败
 */
bool protocol_unsubscribe(protocol_t proto, uint8_t msgid);

/**
 * 发布消息
 * 
 * @param proto 协议实例
 * @param msgid 消息ID(0-255)
 * @param payload 消息负载
 * @param payload_len 负载长度
 * @param need_ack 是否需要ACK
 * @return true 成功
 *         false 失败
 */
bool protocol_publish(protocol_t proto, uint8_t msgid, const uint8_t *payload, size_t payload_len, bool need_ack, uint32_t timeout);

/**
 * 发布消息，并尝试多次发送(重发)
 * 
 * @param proto 协议实例
 * @param msgid 消息ID(0-255)
 * @param payload 消息负载
 * @param payload_len 负载长度
 * @param need_ack 是否需要ACK
 * @param timeout 超时时间(毫秒)
 * @param try_times 尝试次数
 * @return true 成功
 *         false 失败
 */
bool protocol_publish_try(protocol_t proto, uint8_t msgid, const uint8_t *payload, size_t payload_len, bool need_ack, uint32_t timeout, uint32_t try_times);

/**
 * 解析输入的串口数据
 * 
 * @param proto 协议实例
 * @param buffer 输入数据缓冲区
 * @param len 输入数据长度
 * @return true 成功
 *         false 失败
 */
bool protocol_prase(protocol_t proto, uint8_t* buffer, size_t len);

#endif /* __PROTOCOL_H__ */ 

